/*******************************************************************************
 * Copyright (c) 2001, 2002 Boris Pruessmann and others.
 * All rights reserved.   This program and the accompanying materials
 * are made available under the terms of the Common Public License v0.5
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v05.html
 * 
 * Contributors:
 *    Boris Pruessmann - Initial implementation.
 ******************************************************************************/
package net.sourceforge.perforce.ui.dialogs;

import java.util.ArrayList;
import java.util.List;

import net.sourceforge.perforce.api.internal.Spec;
import net.sourceforge.perforce.api.internal.SpecData;
import net.sourceforge.perforce.core.PerforceException;
import net.sourceforge.perforce.core.api.IChangeResult;
import net.sourceforge.perforce.core.api.IPerforceServer;
import net.sourceforge.perforce.core.internal.api.ChangeSpec;
import net.sourceforge.perforce.core.resources.IChangelist;
import net.sourceforge.perforce.ui.internal.Policy;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;

/**
  * @version 	$Revision: 229 $
  * @author		<a href="mailto:bpruessmann@users.sourceforge.net">Boris Pruessmann</a>
  */
public class ChangeSpecDialog extends AbstractChangeSpecDialog
{
	// --------------------------------------------------------------------------- Private Variables

	/** Stores the text for the ok button. */
	private String okButtonText;
	
	/** Holds the Spec object. */
	private Spec spec;

	/** Holds the SpecData object. */
	private SpecData specData;

	// --------------------------------------------------------------- Public Static Factory Methods

	/** Creates a new ChangeSpecDialog for the given server.
	  *
	  * @param parentShell the parent shell
	  * @param server the perforce server.
	  * @param
	  * @return the new ChangeSpecDialog
	  * 
	  * @throws PerforceException in case of an error. 
	  */
	public static final ChangeSpecDialog newInstance(Shell parentShell, IPerforceServer server)
		throws PerforceException
	{		
		ChangeSpecDialog result = new ChangeSpecDialog(parentShell);
		result.okButtonText = Policy.bind("ChangeSpecDialog.okButtonTextUpdate");      //$NON-NLS-1$

		IChangeResult changeResult = server.change((Integer) null);	
		result.specData = changeResult.getChangeSpecData();
		result.spec = changeResult.getChangeSpecDefinition();

		return result;
	}
	
	/** Creates a new ChangeSpecDialog for the given changelist.
	  *
	  * @param parentShell the parent shell
	  * @param changelist the changelist
	  * @param okButtonText text for the ok button
	  * @return the new ChangeSpecDialog
	  * 
	  * @throws PerforceException in case of an error. 
	  */
	public static final ChangeSpecDialog newInstance(
		Shell parentShell, IChangelist changelist, String okButtonText)
		throws PerforceException
	{
		ChangeSpecDialog result = new ChangeSpecDialog(parentShell);
		
		IChangeResult changeResult = changelist.getServer().change(changelist.getId());	
		result.specData = changeResult.getChangeSpecData();
		result.spec = changeResult.getChangeSpecDefinition();
		result.okButtonText = okButtonText;

		return result;
	}
	
	// -------------------------------------------------------------------------------- Constructors
	
	/** @see Dialog#Dialog(org.eclipse.swt.widgets.Shell) */
	ChangeSpecDialog(Shell parentShell)
	{
		super(parentShell);						
	}
	
	// ------------------------------------------------------------------------------ Public Methods
		
	/** Retriebes the complete ChangeSpec that represents the dialog's input.
	  *
	  * @return the changespec. 
	  */
	public ChangeSpec getChangeSpec()
	{
		return new ChangeSpec(spec.format(specData), getFiles());
	}
		
	// --------------------------------------------------------------------------- Protected Methods
	
	/** @see org.eclipse.jface.dialogs.Dialog#createButtonBar(Composite) */
	protected Control createButtonBar(Composite parent) 
	{
		Control result = super.createButtonBar(parent);
		if (okButtonText != null)
		{
			getButton(IDialogConstants.OK_ID).setText(okButtonText);
		}

		String description = getDescriptionText();
		if (description.equals("<enter description here>"))                            //$NON-NLS-1$
		{
			getButton(IDialogConstants.OK_ID).setEnabled(false);
		}
		else
		{
			getButton(IDialogConstants.OK_ID).setEnabled(true);					
		}
		
		return result;
	}
	
	/** @see AbstractChangeSpecDialog#createTableButtonBar(Composite) */
	protected void createTableButtonBar(Composite parent) 
	{
		Composite composite = new Composite(parent, SWT.NULL);
		composite.setFont(parent.getFont());
		
		GridLayout layout = new GridLayout();
		layout.numColumns = 3;
		layout.makeColumnsEqualWidth = true;
		composite.setLayout(layout);
		
		GridData data = 
			new GridData(GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_CENTER);
		composite.setLayoutData(data);

		Button invertSelectionButton = new Button(composite, SWT.PUSH);
		invertSelectionButton.setFont(composite.getFont());
		invertSelectionButton.setText(
			Policy.bind("ChangeSpecDialog.invertSelection"));                          //$NON-NLS-1$
		setTableButtonLayoutData(invertSelectionButton);		
		invertSelectionButton.addSelectionListener(new SelectionAdapter() 
		{
			public void widgetSelected(SelectionEvent event) 
			{
				TableItem[] items = getFileViewer().getTable().getItems();
				for (int i = 0, length = items.length; i < length; i++)
				{			
					boolean selection = items[i].getChecked();
					items[i].setChecked(!selection);
				}
			}
		});
				
		Button selectAllButton = new Button(composite, SWT.PUSH);
		selectAllButton.setFont(composite.getFont());	
		selectAllButton.setText(
			Policy.bind("ChangeSpecDialog.selectAll"));                                //$NON-NLS-1$
		setTableButtonLayoutData(selectAllButton);
		selectAllButton.addSelectionListener(new SelectionAdapter() 
		{
			public void widgetSelected(SelectionEvent event) 
			{
				boolean selection = true;
				changeFileSelection(selection);
			}
		});
			
		Button deselectAllButton = new Button(composite, SWT.PUSH);
		deselectAllButton.setFont(composite.getFont());	
		deselectAllButton.setText(
			Policy.bind("ChangeSpecDialog.deselectAll"));                              //$NON-NLS-1$
		setTableButtonLayoutData(deselectAllButton);
		deselectAllButton.addSelectionListener(new SelectionAdapter() 
		{
			public void widgetSelected(SelectionEvent event) 
			{
				boolean selection = false;
				changeFileSelection(selection);
			}
		});
	}
	
	/** @see Dialog#okPressed() */
	protected void okPressed() 
	{
		specData.replace("Description", getDescriptionText());                         //$NON-NLS-1$
	
		String[] files = getSelectedFiles();		
		for (int i = 0; i < files.length; i++)
		{
			specData.replace("Files" + i, files[i]);                                   //$NON-NLS-1$
		}
		
		for (int i = files.length, length = getFileCount(); i < length; i++)
		{
			specData.replace("Files" + i, "");                           //$NON-NLS-1$ //$NON-NLS-2$
		}
		
		super.okPressed();
	}

	/** @see AbstractChangeSpecDialog#createDescriptionTextControl(Composite, int) */
	protected Text createDescriptionTextControl(Composite composite, int style) 
	{
		return super.createDescriptionTextControl(composite, style);
	}

	// ------------------------------------------------------------------------------------- Methods
	
	/** @see net.sourceforge.perforce.ui.dialogs.AbstractChangeSpecDialog#getTitle() */
	String getTitle() 
	{
		return Policy.bind("ChangeSpecDialog.dialogTitle");                             //NON-NLS-1$
	}

	/** @see AbstractChangeSpecDialog#getDescription() */
	String getDescription()
	{
		return specData.get("Description").trim();                                     //$NON-NLS-1$
	}
		
	/** @see AbstractChangeSpecDialog#getChangelist() */
	String getChangelist()
	{
		return specData.get("Change");                                                 //$NON-NLS-1$
	}	

	/** @see AbstractChangeSpecDialog#getDate() */
	String getDate()
	{
		return specData.get("Date");                                                   //$NON-NLS-1$
	}

	/** @see AbstractChangeSpecDialog#getClientName() */
	String getClientName()
	{
		return specData.get("Client");                                                 //$NON-NLS-1$
	}	
	
	/** @see AbstractChangeSpecDialog#getUserName() */
	String getUserName()
	{
		return specData.get("User");                                                   //$NON-NLS-1$
	}	

	/** @see AbstractChangeSpecDialog#getStatus() */
	String getStatus()
	{
		return specData.get("Status");                                                 //$NON-NLS-1$
	}	
	
	/** @see AbstractChangeSpecDialog#getFiles() */ 
	String[] getFiles()
	{
		List files = new ArrayList();

		int i = 0;
		boolean hasMore = true;
		do
		{
			String filename = specData.get("Files" + i++);                             //$NON-NLS-1$
			if ("".equals(filename))                                                   //$NON-NLS-1$
			{
				hasMore = false;
			}
			else
			{
				files.add(filename);
			}
		}
		while (hasMore);
		
		return (String[]) files.toArray(new String[files.size()]);
	}
	
	// ----------------------------------------------------------------------------- Private Methods
	
	/** Sets the LayoutData for the given 'Table' Button.
	  *
	  * @param button the button 
	  */
	private void setTableButtonLayoutData(Button button) 
	{
		GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
		data.heightHint = convertVerticalDLUsToPixels(IDialogConstants.BUTTON_HEIGHT);
		int widthHint = convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH);
		data.widthHint = 
			Math.max(widthHint, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x);
		button.setLayoutData(data);
	}
	
	/** Changes the selection state of all files to the given value.
	  * 
	  * @param selection new selection value. 
	  */
	private void changeFileSelection(boolean selection) 
	{
		TableItem[] items = getFileViewer().getTable().getItems();
		for (int i = 0, length = items.length; i < length; i++)
		{			
			items[i].setChecked(selection);
		}
	}
}
